package com.benew.ntt.player

import android.content.Context
import android.net.Uri
import com.benew.ntt.player.effect.AwsFXWrapper
import com.benew.ntt.player.utils.ExoPlayerUtils
import com.benew.ntt.player.utils.ExoPlayerUtils.isCacheFile
import com.benew.ntt.player.utils.VolumeUtils
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
import com.google.android.exoplayer2.source.*
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.ntt.core.nlogger.NLogger

class NttExoPlayer(val context: Context) : IPlayer {

    private var mExoPlayer: ExoPlayer?
    private var mPlayerListener: IPlayerListener? = null
    private var mSrcUrl: String? = null
    private val mMainThreadHandler = MainThreadHandler()
    private var mAwsFXWrapper: AwsFXWrapper? = null

    init {
        mExoPlayer = ExoPlayer.Builder(context)
            .setTrackSelector(DefaultTrackSelector(context))
            .setLoadControl(DefaultLoadControl())
            .setHandleAudioBecomingNoisy(false)
            .build().apply {
                addListener(object : Player.Listener {

                    private var state: Int = ExoPlayer.STATE_IDLE

                    override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
                        mPlayerListener?.takeIf { state == ExoPlayer.STATE_READY && !playWhenReady }
                            ?.run {
                                NLogger.d(TAG, "短音频播放状态： 暂停")
                                onPause()
                            }
                    }


                    override fun onIsPlayingChanged(isPlaying: Boolean) {
                        if (state == ExoPlayer.STATE_READY) {
                            mPlayerListener?.takeIf { isPlaying }?.run {
                                NLogger.d(TAG, "短音频播放状态 ： 正在播放")
                                onPlaying()
                            }
                            setEffectEnable(isPlaying)
                        }

                    }

                    override fun onPlaybackStateChanged(playbackState: Int) {
                        state = playbackState
                        when (playbackState) {
                            ExoPlayer.STATE_READY -> {
                                NLogger.d(TAG, "短音频播放状态 ： 准备状态")
                                mPlayerListener?.onPrepared(mSrcUrl)
                            }
                            ExoPlayer.STATE_ENDED -> {
                                NLogger.d(TAG, "短音频播放状态 ： 结束")
                                mPlayerListener?.onComplete(mSrcUrl)
                            }
                            else -> {

                            }
                        }
                    }

                    override fun onPlayerError(error: PlaybackException) {
                        NLogger.d(TAG, "短音频播放播放出错")
                        mPlayerListener?.onError(mSrcUrl, error.errorCode, error.message)
                    }

                })
                mAwsFXWrapper = AwsFXWrapper(this.audioSessionId)
            }
    }

    override fun play(audioItem: AudioItem) {
        audioItem.run {
            mSrcUrl = url
            mMainThreadHandler.runOnMainThread({
                playAudio(this)
            }, null)
        }

    }

    private fun playAudio(audioItem: AudioItem) {
        audioItem.let { audio ->
            mExoPlayer?.run {
                val newVolume = VolumeUtils.calculateBalanceVolume(audio.volume)
                NLogger.i(
                    TAG,
                    "开始播放音频",
                    audio.url,
                    audio.interval,
                    audio.startPoint,
                    audio.endPoint,
                    audio.speed,
                    audio.volume,
                    newVolume
                )
                val newPlaybackParameters =
                    PlaybackParameters(audio.speed, playbackParameters.pitch, newVolume)
                repeatMode = if (audio.repeatCount == -1) {
                    Player.REPEAT_MODE_ALL
                } else {
                    Player.REPEAT_MODE_OFF
                }
                audio.url?.run {
                    val mediaSource =
                        createMediaSource(
                            ExoPlayerUtils.generateUriByType(this, audio.srcType),
                            audio.userAgent
                        )
                    playbackParameters = newPlaybackParameters
                    setMediaSource(
                        addMediaSource(
                            mediaSource,
                            audio.startPoint,
                            audio.endPoint,
                            audio.interval,
                            audio.repeatCount,
                            audio.endInterval,
                            audio.beforeInterval
                        )
                    )
                    prepare()
                    playWhenReady = true
                }
            }
        }
    }

    private fun createMediaSource(uri: Uri, userAgent: String?): MediaSource {
        return if (isCacheFile(uri)) {
            DefaultMediaSourceFactory(context, DefaultExtractorsFactory().apply {
                setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING)
            }).createMediaSource(
                MediaItem.Builder()
                    .setUri(uri)
                    .build()
            )
        } else {
            val httpMediaSourceFactory: MediaSourceFactory = DefaultMediaSourceFactory(
                DefaultHttpDataSource.Factory().setUserAgent(userAgent)
                    .setAllowCrossProtocolRedirects(true).setKeepPostFor302Redirects(true),
                DefaultExtractorsFactory().apply {
                    setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING)
                }
            )
            httpMediaSourceFactory.createMediaSource(
                MediaItem.Builder()
                    .setUri(uri)
                    .build()
            )
        }
    }


    private fun addMediaSource(
        mediaSource: MediaSource,
        startPoint: Long,
        endPoint: Long,
        interval: Int,
        repeatCount: Int,
        endInterval: Int,
        beforeInterval: Int
    ): MediaSource {
        return if (repeatCount > 0)
            ConcatenatingMediaSource(ConcatenatingMediaSource().apply {
                repeat(repeatCount) {
                    addMediaSource(
                        addItemMediaSource(
                            mediaSource,
                            startPoint,
                            endPoint,
                            interval,
                            beforeInterval
                        )
                    )
                }
            }, SilenceMediaSource((endInterval * 1000).toLong()))
        else
            addItemMediaSource(mediaSource, startPoint, endPoint, interval, beforeInterval)
    }

    private fun addItemMediaSource(
        mediaSource: MediaSource,
        startPoint: Long,
        endPoint: Long,
        interval: Int,
        beforeInterval: Int
    ): MediaSource {
        return if (endPoint > startPoint) {
            mediaSource.run {
                ConcatenatingMediaSource(
                    SilenceMediaSource((beforeInterval * 1000).toLong()),
                    ClippingMediaSource(this, startPoint * 1000, endPoint * 1000),
                    SilenceMediaSource((interval * 1000).toLong())
                )
            }
        } else {
            mediaSource.run {
                ConcatenatingMediaSource(
                    SilenceMediaSource((beforeInterval * 1000).toLong()),
                    this,
                    SilenceMediaSource((interval * 1000).toLong())
                )
            }
        }
    }

    /**
     * 设置音效开关
     */
    private fun setEffectEnable(enable: Boolean) {
        mAwsFXWrapper?.isEnabled = enable
    }

    /**
     * 释放音效
     */
    private fun releaseEffect() {
        mAwsFXWrapper?.release()
        mAwsFXWrapper = null
    }


    override fun resume() {
        mMainThreadHandler.runOnMainThread({
            mExoPlayer?.playWhenReady = true
        }, null)
    }

    override fun pause() {
        mMainThreadHandler.runOnMainThread({
            mExoPlayer?.playWhenReady = false
        }, false)
    }

    override fun stop() {
        setEffectEnable(false)
        mMainThreadHandler.runOnMainThread({
            mExoPlayer?.stop()
        }, null)
    }

    override fun isPlaying(): Boolean {
        return mMainThreadHandler.runOnMainThread({
            mExoPlayer?.run {
                playbackState == ExoPlayer.STATE_READY && playWhenReady
            } ?: false
        }, false)
    }

    override fun setPlayListener(playListener: IPlayerListener) {
        mPlayerListener = playListener
    }

    override fun release() {
        releaseEffect()
        mMainThreadHandler.runOnMainThread({
            mExoPlayer?.run {
                release()
            }
            mExoPlayer = null
        }, null)
    }

    companion object {
        const val TAG = "NttExoPlayer"
    }
}